//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_IMAGE_H
#define _UX_IMAGE_H

#include <Includes.h>

namespace Engine
{
namespace Resources
{

	typedef	uint8_array_t		imagedata_t;
	typedef uint32_array_t		mipmapdata_t;

	
	//
	// Image 1D
	//

	struct _EXPORT_ TImage1D
	{
		imagedata_t			aData;
		mipmapdata_t		aMipMaps;	// sizes of mipmaps
		uint				uLength;
		e_tex_format::type	eFormat;
		e_tex_swizzle::type	eSwizzle;
		bool				bCompressed;
		///
		TImage1D():
			uLength(0), eFormat(e_tex_format::UNKNOWN), eSwizzle(e_tex_swizzle::AUTO), bCompressed(false) {}

		TImage1D(const TImage1D &s):
			aData(s.aData), aMipMaps(s.aMipMaps), uLength(s.uLength),
			eFormat(s.eFormat), eSwizzle(s.eSwizzle), bCompressed(s.bCompressed) {}
		
		void Clear()
		{
			eFormat		= e_tex_format::UNKNOWN;
			eSwizzle	= e_tex_swizzle::AUTO;
			uLength		= 0;
			bCompressed	= false;
			aData.Clear();
			aMipMaps.Clear();
		}

		void Swap(TImage1D &sImage)
		{
			aData.SetMem( sImage.aData );
			aMipMaps.SetMem( sImage.aMipMaps );
			uLength		= sImage.uLength;
			eFormat		= sImage.eFormat;
			eSwizzle	= sImage.eSwizzle;
			bCompressed	= sImage.bCompressed;
		}
	};


	//
	// Image 2D
	//

	struct _EXPORT_ TImage2D
	{
		imagedata_t			aData;
		mipmapdata_t		aMipMaps;	// sizes of mipmaps
		uvec2				vTexDim;
		e_tex_format::type	eFormat;
		e_tex_swizzle::type	eSwizzle;
		bool				bCompressed;
		///
		TImage2D():
			eFormat(e_tex_format::UNKNOWN), eSwizzle(e_tex_swizzle::AUTO), bCompressed(false) {}

		TImage2D(const TImage2D &s):
			aData(s.aData), aMipMaps(s.aMipMaps), vTexDim(s.vTexDim),
			eFormat(s.eFormat), eSwizzle(s.eSwizzle), bCompressed(s.bCompressed) {}

		void Clear()
		{
			eFormat		= e_tex_format::UNKNOWN;
			eSwizzle	= e_tex_swizzle::AUTO;
			vTexDim		= uvec2();
			bCompressed	= false;
			aData.Clear();
			aMipMaps.Clear();
		}

		void Swap(TImage2D &sImage)
		{
			aData.SetMem( sImage.aData );
			aMipMaps.SetMem( sImage.aMipMaps );
			vTexDim		= sImage.vTexDim;
			eFormat		= sImage.eFormat;
			eSwizzle	= sImage.eSwizzle;
			bCompressed	= sImage.bCompressed;
		}
	};


	//
	// Image 3D
	//

	struct _EXPORT_ TImage3D
	{
		imagedata_t			aData;
		mipmapdata_t		aMipMaps;	// sizes of mipmaps
		uvec3				vTexDim;
		e_tex_format::type	eFormat;
		e_tex_swizzle::type	eSwizzle;
		bool				bCompressed;
		///
		TImage3D():
			eFormat(e_tex_format::UNKNOWN), eSwizzle(e_tex_swizzle::AUTO), bCompressed(false) {}
		
		TImage3D(const TImage3D &s):
			aData(s.aData), aMipMaps(s.aMipMaps), vTexDim(s.vTexDim),
			eFormat(s.eFormat), eSwizzle(s.eSwizzle), bCompressed(s.bCompressed) {}
			
		void Clear()
		{
			eFormat		= e_tex_format::UNKNOWN;
			eSwizzle	= e_tex_swizzle::AUTO;
			vTexDim		= uvec3();
			bCompressed = false;
			aData.Clear();
			aMipMaps.Clear();
		}

		void Swap(TImage3D &sImage)
		{
			aData.SetMem( sImage.aData );
			aMipMaps.SetMem( sImage.aMipMaps );
			vTexDim		= sImage.vTexDim;
			eFormat		= sImage.eFormat;
			eSwizzle	= sImage.eSwizzle;
			bCompressed	= sImage.bCompressed;
		}
	};


	//
	// Sprite 2D
	//

	struct _EXPORT_ TSprite2D
	{
		struct TAnimInfo
		{
			string		sName;
			uint		uOffset;	// offset in frame array
			uint		uCount;		// frames count
			float		fFrameRate;
			///
			TAnimInfo(): uOffset(0), uCount(0), fFrameRate(0.f) {}
			TAnimInfo(const char *name, uint offset, uint count, float rate):
				sName(name), uOffset(offset), uCount(count), fFrameRate(rate) {}
		};

		struct TAnimFrame
		{
			uint		uIndex;
			color4u		sColor;
			///
			TAnimFrame(): uIndex(0) {}
		};

		TImage2D			sImage;
		array< frect >		aTexcoords;
		array< TAnimFrame >	aFrames;
		array< TAnimInfo >	aAnimation;
		///
		TSprite2D() {}

		TSprite2D(const TSprite2D &s):
			sImage(s.sImage), aTexcoords(s.aTexcoords), aFrames(s.aFrames), aAnimation(s.aAnimation) {}

		void Clear()
		{
			sImage.Clear();
			aFrames.Clear();
			aTexcoords.Clear();
			aAnimation.Clear();
		}

		void Swap(TSprite2D &sSprite)
		{
			sImage.Swap( sSprite.sImage );
			aTexcoords.SetMem( sSprite.aTexcoords );
			aAnimation.SetMem( sSprite.aAnimation );
			aFrames.SetMem( sSprite.aFrames );
		}
	};


	struct _EXPORT_ Image
	{
		static float GetInternalBPP(e_tex_format::type eFormat);
		static uint  GetPixelDataBPP(e_tex_format::type eFormat);

		static bool ScalePOT(const TImage2D &sImage, int iPow);
		static bool ScalePOT(const TImage3D &sImage, int iPow);
	
		static bool ConvertFormat(e_tex_format::type eFormat, bool comp, GLenum &ifmt, GLenum &fmt, GLenum &type);
		static bool DeconvertFormat(GLenum ifmt, GLenum fmt, GLenum type, e_tex_format::type &eFormat);
	
		static GLenum	GetInternalFormat(e_tex_format::type eFormat);
		static GLenum	GetColorFormat(e_tex_format::type eFormat);
		static GLenum	GetColorValueType(e_tex_format::type eFormat);
	
		static uint	GetColorChannels(e_tex_format::type eFormat);
		static uint	GetColorChannelsI(e_tex_format::type eInternalFormat);

		static bool	GetInternalFormat(GLenum ifmt, e_tex_format::type &eFormat);
		static bool	GetColorFormat(GLenum fmt, e_tex_format::type &eFormat);
		static bool	GetColorValueType(GLenum type, e_tex_format::type &eFormat);

		static bool	GetSwizzle(e_tex_swizzle::type eSwizzle, GLint swizzle[4]);
		static bool	AutoSwizzle(e_tex_format::type eFormat, e_tex_swizzle::type &eSwizzle);
		static bool	SetSwizzle(const GLint swizzle[4], e_tex_swizzle::type &eSwizzle);
	
		static bool Compress(e_tex_format::type &eFormat);
		static bool CompressI(GLenum &ifmt);
		static bool IsCompressed(e_tex_format::type eFormat);
		static bool IsSameTypes(e_tex_format::type eIFormat1, e_tex_format::type eIFormat2);
		static bool CompareInternalFormats(e_tex_format::type eFormat1, e_tex_format::type eFormat2);
		static bool ComparePixelFormats(e_tex_format::type eFormat1, e_tex_format::type eFormat2);

		static void GetCompareFunc(e_tex_flags::type eFlags, GLint &param);
		static void GetAnisotropy(e_tex_flags::type eFlags, GLint &param);

		static bool RenderTargetFormatToTextureFormat(e_rt_format::type eRTFormat, e_tex_format::type &eTexFormat);
		static bool TextureFormatToRenderTargetFormat(e_tex_format::type eTexFormat, e_rt_format::type &eRTFormat);
		static e_tex_format::type GetTexFormat(e_rt_format::type eRTFormat);
		
		static const char * GetInternalFormatName(e_tex_format::type eFormat);
		static const char * GetColorFormatName(e_tex_format::type eFormat);
		static const char * GetColorValueTypeName(e_tex_format::type eFormat);
	};

//-------------------------------------------------------------------

}	// EngineResource
}	// Engine

#endif	// _UX_IMAGE_H